use std::ops::{Deref, DerefMut};
use std::rc::Rc;

use crate::gen_title;

pub fn ch4_6_1() {
    gen_title("ch4_6_1", 18);

    #[derive(Debug)]
    struct Person {
        name: String,
        age: u8,
    }

    impl Person {
        fn new(name: String, age: u8) -> Self {
            Person { name, age }
        }

        fn display(self: &mut Person, age: u8) {
            println!("{}", age);
            let Person { name, age } = &self;
            println!("name: {}, age: {}", name, age);
        }
    }

    let mut person = Person::new("Tom".to_string(), 18);
    person.display(12);
}

pub fn ch4_6_2() {
    gen_title("ch4_6_2", 18);

    let x = 5;
    let y = &x;

    println!("x: {}, y: {}", x, *y);
}

pub fn ch4_6_3() {
    gen_title("ch4_6_3", 18);

    let x = Box::new(1);
    let sum = *x + 1;
    println!("sum: {}", sum);
}

pub fn ch4_6_4() {
    gen_title("ch4_6_4", 18);

    struct MyBox<T>(T);

    impl<T> MyBox<T> {
        fn new(x: T) -> MyBox<T> {
            MyBox(x)
        }
    }

    impl<T> Deref for MyBox<T> {
        type Target = T;

        fn deref(&self) -> &Self::Target {
            &self.0
        }
    }

    let y = MyBox::new(5);
    println!("y: {}", *y);
}

pub fn ch4_6_5() {
    gen_title("ch4_6_5", 18);

    let s = String::from("hello world");
    display(&s);

    fn display(s: &str) {
        println!("{}", s);
    }
}

pub fn ch4_6_6() {
    gen_title("ch4_6_6", 18);

    struct MyBox<T>(T);

    impl<T> MyBox<T> {
        fn new(x: T) -> MyBox<T> {
            MyBox(x)
        }
    }

    impl<T> Deref for MyBox<T> {
        type Target = T;

        fn deref(&self) -> &Self::Target {
            &self.0
        }
    }

    let s = MyBox::new(String::from("hello world"));
    display(&s);

    display(&(*s)[..]);

    fn display(s: &str) {
        println!("{}", s);
    }
}

pub fn ch4_6_7() {
    gen_title("ch4_6_7", 18);

    struct MyBox<T>(T);

    impl<T> MyBox<T> {
        fn new(x: T) -> MyBox<T> {
            MyBox(x)
        }
    }

    impl<T> Deref for MyBox<T> {
        type Target = T;

        fn deref(&self) -> &Self::Target {
            &self.0
        }
    }

    let s = MyBox::new(String::from("Hello, world"));
    let s1: &str = &s;
    let s2: String = s.to_string();
    println!("s1: {}, s2: {}", s1, s2);
}

pub fn ch4_6_8() {
    gen_title("ch4_6_8", 18);

    fn foo(s: &str) {
        println!("{}", s);
    }

    let owned = "Hello".to_string();
    let counted = Rc::new(owned);

    foo(&counted);
}

pub fn ch4_6_9() {
    gen_title("ch4_6_9", 18);

    struct Foo;

    impl Foo {
        fn foo(&self) {
            println!("Foo");
        }
    }

    let f = &&Foo;

    f.foo();
    (&f).foo();
    (&&f).foo();
    (&&&&&&&&&f).foo();
}

pub fn ch4_6_10() {
    gen_title("ch4_6_10", 18);

    struct MyBox<T> {
        v: T,
    }

    impl<T> MyBox<T> {
        fn new(x: T) -> MyBox<T> {
            MyBox { v: x }
        }
    }

    impl<T> Deref for MyBox<T> {
        type Target = T;

        fn deref(&self) -> &Self::Target {
            &self.v
        }
    }

    impl<T> DerefMut for MyBox<T> {
        fn deref_mut(&mut self) -> &mut Self::Target {
            &mut self.v
        }
    }

    let mut s = MyBox::new(String::from("hello, "));
    display(&mut s);

    fn display(s: &mut String) {
        s.push_str("world");
        println!("{}", s);
    }
}
